// Copyright 2014 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
 
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

#include "../../../include/fxge/fx_freetype.h"
#include "../../../../third_party/freetype/src/psnames/pstables.h"

static int xyq_search_node(char* glyph_name, int name_offset, int table_offset, wchar_t unicode)
{
    int i, count;

    // copy letters
    while (1) {
        glyph_name[name_offset] = ft_adobe_glyph_list[table_offset] & 0x7f;
        name_offset++;
        table_offset++;
        if (!(ft_adobe_glyph_list[table_offset - 1] & 0x80)) break;
    }
    glyph_name[name_offset] = 0;

    // get child count
    count = ft_adobe_glyph_list[table_offset] & 0x7f;

    // check if we have value for this node
    if (ft_adobe_glyph_list[table_offset] & 0x80) {
        unsigned short thiscode = ft_adobe_glyph_list[table_offset + 1] * 256 + ft_adobe_glyph_list[table_offset + 2];
        if (thiscode == (unsigned short)unicode)	// found it!
            return 1;
        table_offset += 3;
    }
    else
        table_offset++;

    // now search in sub-nodes
    if (count == 0) return 0;
    for (i = 0; i < count; i++) {
        int child_offset = ft_adobe_glyph_list[table_offset + i * 2] * 256 + ft_adobe_glyph_list[table_offset + i * 2 + 1];
        if (xyq_search_node(glyph_name, name_offset, child_offset, unicode))
            // found in child
            return 1;
    }
    return 0;
}

#define VARIANT_BIT         0x80000000UL

int FXFT_unicode_from_adobe_name(const char*  glyph_name)
{
    /* If the name begins with `uni', then the glyph name may be a */
    /* hard-coded unicode character code.                          */
    if (glyph_name[0] == 'u' &&
        glyph_name[1] == 'n' &&
        glyph_name[2] == 'i')
    {
        /* determine whether the next four characters following are */
        /* hexadecimal.                                             */

        /* XXX: Add code to deal with ligatures, i.e. glyph names like */
        /*      `uniXXXXYYYYZZZZ'...                                   */

        FT_Int       count;
        FT_UInt32    value = 0;
        const char*  p = glyph_name + 3;


        for (count = 4; count > 0; count--, p++)
        {
            char          c = *p;
            unsigned int  d;


            d = (unsigned char)c - '0';
            if (d >= 10)
            {
                d = (unsigned char)c - 'A';
                if (d >= 6)
                    d = 16;
                else
                    d += 10;
            }

            /* Exit if a non-uppercase hexadecimal character was found   */
            /* -- this also catches character codes below `0' since such */
            /* negative numbers cast to `unsigned int' are far too big.  */
            if (d >= 16)
                break;

            value = (value << 4) + d;
        }

        /* there must be exactly four hex digits */
        if (count == 0)
        {
            if (*p == '\0')
                return value;
            if (*p == '.')
                return (FT_UInt32)(value | VARIANT_BIT);
        }
    }

    /* If the name begins with `u', followed by four to six uppercase */
    /* hexadecimal digits, it is a hard-coded unicode character code. */
    if (glyph_name[0] == 'u')
    {
        FT_Int       count;
        FT_UInt32    value = 0;
        const char*  p = glyph_name + 1;


        for (count = 6; count > 0; count--, p++)
        {
            char          c = *p;
            unsigned int  d;


            d = (unsigned char)c - '0';
            if (d >= 10)
            {
                d = (unsigned char)c - 'A';
                if (d >= 6)
                    d = 16;
                else
                    d += 10;
            }

            if (d >= 16)
                break;

            value = (value << 4) + d;
        }

        if (count <= 2)
        {
            if (*p == '\0')
                return value;
            if (*p == '.')
                return (FT_UInt32)(value | VARIANT_BIT);
        }
    }

    /* Look for a non-initial dot in the glyph name in order to */
    /* find variants like `A.swash', `e.final', etc.            */
    {
        const char*  p = glyph_name;
        const char*  dot = NULL;


        for (; *p; p++)
        {
            if (*p == '.' && p > glyph_name)
            {
                dot = p;
                break;
            }
        }

        /* now look up the glyph in the Adobe Glyph List */
        if (!dot)
            return (FT_UInt32)ft_get_adobe_glyph_index(glyph_name, p);
        else
            return (FT_UInt32)(ft_get_adobe_glyph_index(glyph_name, dot) |
            VARIANT_BIT);
    }
}

void FXFT_adobe_name_from_unicode(char* glyph_name, wchar_t unicode)
{
    int i, count;

    // start from top level node
    count = ft_adobe_glyph_list[1];
    for (i = 0; i < count; i++) {
        int child_offset = ft_adobe_glyph_list[i * 2 + 2] * 256 + ft_adobe_glyph_list[i * 2 + 3];
        if (xyq_search_node(glyph_name, 0, child_offset, unicode))
            return;
    }

    // failed, clear the buffer
    glyph_name[0] = 0;
}
